package lib

import (
	"GameServer/Common/data"
	"GameServer/Common/utils"
	"GameServer/Game/errors"
	"GameServer/Game/m"
	"fmt"
	"sort"
	"strconv"
)

// 给玩家成就添加进度
func AddAchievProgress(u *m.User, achType int64, val int64) {
	switch achType {
	case data.AchievementType.Treasure: //挖矿
		AchievCumulative(u, achType, val)
	case data.AchievementType.Get_gold: //获取金币
		AchievCumulative(u, achType, val)
	case data.AchievementType.Get_chest: // 获得宝箱
		AchievCumulative(u, achType, val)
	case data.AchievementType.Pick_gold: // 拾取金币
		AchievCumulative(u, achType, val)
	case data.AchievementType.Progress_card: // 关卡进度
		AchievGrowth(u, achType, val) // 可特殊处理
	case data.AchievementType.Clear_card: // 清空关卡
		AchievCumulative(u, achType, val)
	case data.AchievementType.SlotGoblin: // 老虎机哥布林次数
		AchievCumulative(u, achType, val)
	case data.AchievementType.SlotFire: // 老虎机放火次数
		AchievCumulative(u, achType, val)
	case data.AchievementType.Get_sheild: // 获得盾牌
		AchievCumulative(u, achType, val)
	case data.AchievementType.Pick_alter: // 开启祭坛
		AchievCumulative(u, achType, val)
	case data.AchievementType.Pick_bomb: // 开启炸弹
		AchievCumulative(u, achType, val)
	case data.AchievementType.Pick_Crystalball: // 开启占卜
		AchievCumulative(u, achType, val)
	case data.AchievementType.Get_Gems: // 获得宝石
		AchievCumulative(u, achType, val)
	case data.AchievementType.Use_spins: // 消耗体力
		AchievCumulative(u, achType, val)
	case data.AchievementType.Collect_cards: // 收集卡牌
		AchievCumulative(u, achType, val)
	case data.AchievementType.Destroy_cards: // 摧毁卡牌
		// 没有这个功能
	case data.AchievementType.Kind_pet: // 宠物类别，玩家拥有宠物个数
		AchievGrowth(u, achType, val) // 成长成就
	case data.AchievementType.Level_pet: // 宠物等级
		AchievGrowth(u, achType, val) // 成长成就
	case data.AchievementType.DiffLevel_pet: // 4个不同等级的宠物
		AchievGrowth(u, achType, val) // 成长成就
	case data.AchievementType.HideShop_purchase: // 神秘商店购买物品
		AchievCumulative(u, achType, val)
	case data.AchievementType.Invite_friends: // 邀请好友
		// 没有这个功能
	case data.AchievementType.SendGift_friends: // 赠礼好友礼品
		AchievCumulative(u, achType, val)
	case data.AchievementType.Send_spins: // 赠送体力
		AchievCumulative(u, achType, val)
	case data.AchievementType.Gold_kill: // 金币击杀怪物
		AchievCumulative(u, achType, val)
	case data.AchievementType.Monster_kill: // 击杀怪物
		AchievCumulative(u, achType, val)
	case data.AchievementType.Watch_ads: // 观看广告
		AchievCumulative(u, achType, val)
	case data.AchievementType.Join_guild: // 加入公会
		AchievCumulative(u, achType, val)
	case data.AchievementType.Hoard_gold: // 囤积金币
		AchievGrowth(u, achType, val) // 特殊处理 记录历史最大值
	case data.AchievementType.Spins_one_day: // 一天内消耗体力
		AchievGrowth(u, achType, val) // 特殊处理
	case data.AchievementType.Refresh_hideShop: // 刷新神秘商店
		AchievCumulative(u, achType, val)
	case data.AchievementType.Wake_pet: // 宠物觉醒时间
		AchievCumulative(u, achType, val)
	case data.AchievementType.Get_HideLevelCards: // 获得高级卡牌
		AchievGrowth(u, achType, val) // 特殊处理
	case data.AchievementType.Get_stars: // 获得星星
		AchievGrowth(u, achType, val)
	case data.AchievementType.NotOpen_block: // 过关并且不打开部分格子
		AchievGrowth(u, achType, val) // 特殊处理
	case data.AchievementType.OpenBlock_withinTiger: // 连续打开砖块且不消耗体力
		AchievGrowth(u, achType, val) // 成长成就
	case data.AchievementType.Receive_gift: // 接受好友赠礼
		AchievCumulative(u, achType, val)
	default:
		fmt.Println("没有对应的成就类型", achType)
	}
}

// 获取玩家成就进度 用户 成就tid 成就类型
func GetAchievProgress(from string, u *m.User, tid int64, achType int64, PSend func(interface{}) error) (uProp *m.UpdateProp, err error) {
	ua, _ := u.GetUserAchiev(u.Uid.Hex())
	at, _ := u.GetAchievTotal(u.Uid.Hex())
	ai, ok := ua.AchievInfos[achType]
	if !ok {
		err = errors.NewErrcode(data.Errcode.ServerErr, "没有该类型的成就")
		return
	}
	achievTpl, ok := data.Get("Achievements", uint64(tid))
	if !ok {
		err = errors.NewErrcode(data.Errcode.ConfigNotFound, "没有找到该配置表Achievements")
		return
	}
	achievT := achievTpl.(data.Achievement)

	progress, _ := strconv.ParseInt(achievT.Progress, 10, 64)
	// 成就没有达到阀值
	if progress > ai.Progress {
		err = errors.NewErrcode(data.Errcode.ServerErr, "成就没有达到阀值")
		return
	}
	// 领取的成绩，标记状态为2、已领取
	for _, item := range ai.AchievLst {
		if item.Tid == tid {
			if item.State == 2 {
				err = errors.NewErrcode(data.Errcode.ServerErr, "该奖励已经领取，不能再领取。")
				return
			}
			item.State = 2
			break
		}
	}
	reward := int64(achievT.Reward)
	// 累计成就 累计星星
	at.StarAchiev += reward
	at.StarCur += reward
	at.Update(at)

	ua.Update(ua)

	uProp, _, _, err = GiveGoodsByKv(from, u, m.BaseKV{Key: data.GlobalEnum.StarAchiev, Val: reward}, PSend)
	return
}

// 领取成就累计的奖励
func AchievTotalRecvReward(u *m.User) (r []m.BaseKV, err error) {
	at, _ := u.GetAchievTotal(u.Uid.Hex())
	tplList, ok := data.GetAllDatas("AchiveReward1s")
	if !ok {
		err = errors.NewErrcode(data.Errcode.ConfigNotFound, "AchiveReward1s")
		return
	}
	// 获取配表的数据无序，需要按照id排序。
	sort.Slice(tplList, func(i int, j int) bool {
		achi := tplList[i].(data.AchiveReward1)
		achj := tplList[j].(data.AchiveReward1)
		return achi.Id < achj.Id
	})

	r = make([]m.BaseKV, 0)
	for _, item := range tplList {
		itemT := item.(data.AchiveReward1)
		if int64(itemT.Id) == at.Tid {
			activItemQuantity := int64(itemT.ActivItemQuantity)
			// 当前的星星数量大于等于轮数上的星星数量
			if activItemQuantity <= at.StarCur {
				// 扣掉轮的阀值
				at.StarCur -= activItemQuantity
				// 增加用户的轮数
				at.Tid += 1
				// 获取奖励道具
				r = append(r, m.BaseKV{
					Key: int64(itemT.ItemID),
					Val: int64(itemT.Rewards),
				})
			} else { // 当前星星小于阀值，退出循环。
				break
			}
		}
	}
	at.Update(at)

	return
}

// 成就累计
func AchievCumulative(u *m.User, achType int64, val int64) (err error) {
	ua, _ := u.GetUserAchiev(u.Uid.Hex())
	defer ua.Update(ua)

	achievInfos, ok := ua.AchievInfos[achType]
	if !ok {
		// 没有该进度，需要加载
		tplList, ok := data.Filters("Achievements", func(val interface{}) bool {
			valT := val.(data.Achievement)
			return int64(valT.AchType) == achType
		})
		if !ok {
			fmt.Println("没有找到Achievements配置表")
			err = errors.NewErrcode(data.Errcode.ConfigNotFound, "没有找到Achievements配置表")
			return
		}
		// 创建该类型的成就
		achievInfos = &m.AchievInfo{
			AchievType: achType,
			Progress:   0,
			AchievLst:  make([]*m.Achiev, 0),
		}
		ua.AchievInfos[achType] = achievInfos
		// 初始化成就列表
		for _, item := range tplList {
			itemT := item.(data.Achievement)
			progress, _ := strconv.ParseInt(itemT.Progress, 10, 64)
			// 给用户添加成就
			achievInfos.AchievLst = append(achievInfos.AchievLst, &m.Achiev{
				Tid:      int64(itemT.Id),
				State:    0,
				Progress: progress,
			})
		}
	}
	// 增加进度
	achievInfos.Progress += val
	alen := len(achievInfos.AchievLst)
	achT := achievInfos.AchievLst[alen-1]
	// 1、当成就进度小于零，就是累计数据溢出
	// 2、当成就进度大于最大阀值
	// 直接将进度赋值最大阀值
	if achievInfos.Progress < 0 || achievInfos.Progress > achT.Progress {
		achievInfos.Progress = achT.Progress
	}

	aa, _ := u.GetAchievAuxiliary(u.Uid.Hex())
	defer aa.Update(aa)

	// 修改成就状态
	for _, item := range achievInfos.AchievLst {
		// 成就状态为0 并且 成就进度 >= 成就阈值，状态改为完成。
		if item.State == 0 && achievInfos.Progress >= item.Progress {
			item.State = 1

			aa.AchievChange = append(aa.AchievChange, item.Tid)
		}
	}
	return
}

// 成长成就 记录最大值
func AchievGrowth(u *m.User, achType int64, val int64) (err error) {
	ua, _ := u.GetUserAchiev(u.Uid.Hex())
	defer ua.Update(ua)

	achievInfos, ok := ua.AchievInfos[achType]
	if !ok {
		// 后期创建
		fmt.Println("没有该类型的成就", achType)
		return
	}
	// 记录最大值
	if achievInfos.Progress < val {
		aa, _ := u.GetAchievAuxiliary(u.Uid.Hex())
		defer aa.Update(aa)

		achievInfos.Progress = val
		// 修改成就状态
		for _, item := range achievInfos.AchievLst {
			// 成就状态为0 并且 成就进度 >= 成就阈值，状态改为完成。
			if item.State == 0 && achievInfos.Progress >= item.Progress {
				item.State = 1

				aa.AchievChange = append(aa.AchievChange, item.Tid)
			}
		}
	}
	return
}

// 创建成就
func CreateAchievement(u *m.User) (err error) {
	// 没有该进度，需要加载
	tplList, ok := data.GetAllDatas("Achievements")
	if !ok {
		fmt.Println("没有找到Achievements配置表")
		err = errors.NewErrcode(data.Errcode.ConfigNotFound, "没有找到Achievements配置表")
		return
	}

	sort.Slice(tplList, func(i int, j int) bool {
		achi := tplList[i].(data.Achievement)
		achj := tplList[j].(data.Achievement)
		return achi.Id < achj.Id
	})

	// 生成成就信息
	au := &m.UserAchiev{
		Uid:         u.Uid,
		AchievInfos: make(map[int64]*m.AchievInfo),
	}
	au.Update(au)
	// 成就辅助信息
	aa := &m.AchievAuxiliary{
		Uid: u.Uid,
	}
	aa.Update(aa)

	// 初始第一轮
	// 生成累计成就信息
	at := &m.AchievTotal{
		Uid:        u.Uid,
		Tid:        1,
		StarCur:    0,
		StarAchiev: 0,
	}
	at.Update(at)

	for _, item := range tplList {
		itemT := item.(data.Achievement)
		achType := int64(itemT.AchType)
		ai, ok := au.AchievInfos[achType]
		if !ok {
			ai = &m.AchievInfo{
				AchievType: achType,
				Progress:   0,
				AchievLst:  make([]*m.Achiev, 0),
			}
			au.AchievInfos[achType] = ai
		}

		progress, _ := strconv.ParseInt(itemT.Progress, 10, 64)
		ai.AchievLst = append(ai.AchievLst, &m.Achiev{
			Tid:      int64(itemT.Id),
			State:    0,
			Progress: progress,
		})
	}

	// 将一些成就进度累计，方便计算。
	for key, val := range au.AchievInfos {
		switch key {
		case data.AchievementType.Progress_card, data.AchievementType.DiffLevel_pet, data.AchievementType.Get_HideLevelCards:
			clt := val.AchievLst[0].Progress
			for i := 1; i < len(val.AchievLst); i++ {
				clt += val.AchievLst[i].Progress
				val.AchievLst[i].Progress = clt
			}
		}
	}
	au.Update(au)

	u.StarAchiev = 0
	u.Update(u)
	return
}

// 重置成就信息
// func ResetAchievement(u *m.User) (err error) {
// 	// 没有该进度，需要加载
// 	tplList, ok := data.GetAllDatas("Achievements")
// 	if !ok {
// 		fmt.Println("没有找到Achievements配置表")
// 		err = errors.NewErrcode(data.Errcode.ConfigNotFound, "没有找到Achievements配置表")
// 		return
// 	}

// 	sort.Slice(tplList, func(i int, j int) bool {
// 		achi := tplList[i].(data.Achievement)
// 		achj := tplList[j].(data.Achievement)
// 		return achi.Id < achj.Id
// 	})

// 	// 生成成就信息
// 	au := &m.UserAchiev{
// 		Uid:         u.Uid,
// 		AchievInfos: make(map[int64]*m.AchievInfo),
// 	}
// 	au.Update(au)
// 	// 成就辅助信息
// 	aa := &m.AchievAuxiliary{
// 		Uid: u.Uid,
// 	}
// 	aa.Update(aa)

// 	// 生成累计成就信息，初始化为第一轮成就。
// 	at := &m.AchievTotal{
// 		Uid:        u.Uid,
// 		Tid:        1,
// 		StarCur:    0,
// 		StarAchiev: 0,
// 	}
// 	at.Update(at)

// 	for _, item := range tplList {
// 		itemT := item.(data.Achievement)
// 		achType := int64(itemT.AchType)
// 		ai, ok := au.AchievInfos[achType]
// 		if !ok {
// 			ai = &m.AchievInfo{
// 				AchievType: achType,
// 				Progress:   0,
// 				AchievLst:  make([]*m.Achiev, 0),
// 			}
// 			au.AchievInfos[achType] = ai
// 		}

// 		progress, _ := strconv.ParseInt(itemT.Progress, 10, 64)
// 		ai.AchievLst = append(ai.AchievLst, &m.Achiev{
// 			Tid:      int64(itemT.Id),
// 			State:    0,
// 			Progress: progress,
// 		})
// 	}

// 	// 将一些成就进度累计，方便计算。
// 	for key, val := range au.AchievInfos {
// 		switch key {
// 		case data.AchievementType.Progress_card, data.AchievementType.DiffLevel_pet, data.AchievementType.Get_HideLevelCards:
// 			clt := val.AchievLst[0].Progress
// 			for i := 1; i < len(val.AchievLst); i++ {
// 				clt += val.AchievLst[i].Progress
// 				val.AchievLst[i].Progress = clt
// 			}
// 		}
// 	}
// 	au.Update(au)
// 	return
// }

// 成就，记录相同宠物等级个数
func AchievDiffLevelPet(u *m.User) {
	tplList, ok := data.Filters("Achievements", func(val interface{}) bool {
		valT := val.(data.Achievement)
		return int64(valT.AchType) == data.AchievementType.DiffLevel_pet
	})
	if !ok {
		fmt.Println("Achievements 获取配置表失败")
		return
	}

	sort.Slice(tplList, func(i int, j int) bool {
		achi := tplList[i].(data.Achievement)
		achj := tplList[j].(data.Achievement)
		return achi.Id < achj.Id
	})

	level := int64(0)
	// 不同宠物，在限制等级以上，限制等级5、10、20、30、40
	uPet := u.GetUserPet()
	for _, item := range tplList {
		itemT := item.(data.Achievement)
		num := int64(itemT.Auxi[0])
		lv := int64(itemT.Auxi[1])
		// 满足等级宠物个数
		cnt := int64(0)
		// 遍历宠物
		for _, pet := range uPet.Pets {
			if pet.Status != 1 { // 没有激活不加
				continue
			}
			if pet.Lv >= lv { // 宠物等级大于等于限制等级，计数加一
				cnt++
			}
		}
		if cnt == num {
			level = lv
		}
	}
	AddAchievProgress(u, data.AchievementType.DiffLevel_pet, level)
}

// 修改成就进度
func ModifyAchievement(u *m.User, achType int64, val int64) {
	ua, _ := u.GetUserAchiev(u.Uid.Hex())

	if ai, ok := ua.AchievInfos[achType]; ok {
		ai.Progress = val
		ua.Update(ua)
	}
}

// 消耗体力，重置连续打开的格子数
func AchievAuxiliResetCOG(u *m.User) {
	aa, _ := u.GetAchievAuxiliary(u.Uid.Hex())
	aa.ContinuityOpenGrid = 0
	aa.Update(aa)
}

// 打开格子，累计打开格子数
func AchievAuxiliAddCOG(u *m.User, num int64) {
	aa, _ := u.GetAchievAuxiliary(u.Uid.Hex())
	aa.ContinuityOpenGrid += num
	aa.Update(aa)
	// 更新不消耗体力，连续打开的格子数。
	AddAchievProgress(u, data.AchievementType.OpenBlock_withinTiger, aa.ContinuityOpenGrid)
}

// 记录一天内消耗的体力
func AchievAuxiliOD(u *m.User, num int64) {
	aa, _ := u.GetAchievAuxiliary(u.Uid.Hex())
	// 获取当前时间
	nowTime := utils.TNow()
	// 如果当前时间-一天起始时间>一天，需要重置 一天起始时间和一天累计的体力
	if nowTime.Unix()-aa.OneDayTime > 86400 {
		aa.OneDayTime = utils.ZeroTime(nowTime) // 重置凌晨时间
		aa.OneDayEnergy = 0                     // 重置体力
	}

	aa.OneDayEnergy += num // 累计体力
	aa.Update(aa)

	// 更新一天内消耗的体力最大值
	AddAchievProgress(u, data.AchievementType.Spins_one_day, aa.OneDayEnergy)
}

// 成就，开启一个宝箱
func AchievBoxCard(u *m.User, boxResList []*m.BoxRes) {
	tplList, ok := data.Filters("Goods", func(val interface{}) bool {
		tplGood := val.(data.Good)
		for _, item := range boxResList { // 遍历宝箱
			for _, itemL := range item.Res { // 遍历宝箱中的物品
				if itemL.Tid == int64(tplGood.Id) {
					return true
				}
			}
		}
		return false
	})
	if !ok {
		fmt.Println("AchievBoxCard Goods 读取配表失败")
		return
	}
	tplListAch, ok := data.Filters("Achievements", func(val interface{}) bool {
		tplAch := val.(data.Achievement)
		return int64(tplAch.AchType) == data.AchievementType.Get_HideLevelCards
	})
	if !ok {
		fmt.Println("AchievBoxCard Achievements 读取配表失败")
		return
	}
	cnt := int64(0) // 符合成就的个数
	for _, itemA := range tplListAch {
		itemAc := itemA.(data.Achievement)
		num := itemAc.Auxi[0]  // 卡片数量
		star := itemAc.Auxi[1] // 卡片星星
		cntT := uint64(0)      // 符合星级道具的数量
		for _, item := range tplList {
			itemT := item.(data.Good)
			if itemT.Owner > 0 && itemT.Star >= star { // 道具星星大于等于要求，计数加1
				cntT++
			}
		}
		// 箱子中的道具符合要求，计数加1
		if num <= cntT {
			cnt++
		}
	}

	AddAchievProgress(u, data.AchievementType.Get_HideLevelCards, cnt)
}

// 成就，判断当前关卡是否打开所有格子
func AchievOpenAllGrids(u *m.User) {
	lockBlock, ok := u.GetLockBlock(u.Pos.LockBlockTid)
	if !ok {
		return
	}
	// 打开的格子数等于格子总数，成就
	if lockBlock.GridOpenNum == lockBlock.GridNum {
		AddAchievProgress(u, data.AchievementType.Clear_card, 1)
	}
}

// 成就，记录未开格子数，通关
func AchievSurplusAllGrids(u *m.User) {
	lockBlock, ok := u.GetLockBlock(u.Pos.LockBlockTid)
	if !ok {
		return
	}
	// 未打开格子数
	cnt := lockBlock.GridNum - lockBlock.GridOpenNum
	AddAchievProgress(u, data.AchievementType.NotOpen_block, cnt)
}

// 成就，抵达关卡
func AchievArrivallevel(u *m.User) {
	tplListAch, ok := data.Filters("Achievements", func(val interface{}) bool {
		tplAch := val.(data.Achievement)
		return int64(tplAch.AchType) == data.AchievementType.Progress_card
	})
	if !ok {
		fmt.Println("AchievBoxCard Achievements 读取配表失败")
		return
	}
	for idx, item := range tplListAch {
		itemT := item.(data.Achievement)
		lockG := int64(itemT.Auxi[0])
		lockS := int64(itemT.Auxi[1])
		if (lockG-1)*7+lockS == u.MaxPos.LockBlockTid {
			// 成就，记录用户关卡进度。
			AddAchievProgress(u, data.AchievementType.Progress_card, int64(idx+1))
			break
		}
	}
}

// 获取已经完成的成就tid
func AchievComplete(u *m.User) (r []int64) {
	aa, _ := u.GetAchievAuxiliary(u.Uid.Hex())
	r = make([]int64, 0)
	for _, item := range aa.AchievChange {
		r = append(r, item)
	}
	// 清除掉完成的成就
	aa.AchievChange = make([]int64, 0)
	aa.Update(aa)
	return
}
